import { getLogger, type OptionalFields } from '@gnlab/utils'
import { type MemStream } from '@gnlab/utils/rx'
import { mmap } from '@gnlab/utils/rx'
import pick from 'lodash/pick'
import { safeJSONParse } from '@/lib/utils'
import { ContactType } from '@/services/contacts'
import { configSubject as newRankConfigSubject } from '@/services/features/new-rank'

export const logger = getLogger('services/features/chat-sidebars')

export interface BaseSidebar {
  key: string // id 是后端用的唯一标识；key 是前端用的唯一标识（因为系统侧边栏大部分情况并没有 id）
  name: string // 标题
  scope: ContactType[] // 支持哪些联系人类型
  disabled: boolean // 是否已禁用
}
export interface SystemSidebar extends BaseSidebar {
  system: true
  id?: number // 没有 id 代表没有把配置保存到后端
  supportObserving: boolean // 能否在观察者模式下使用，默认为 false
  reset: boolean // 是否需要在联系人变化时重置组件状态。默认为 true 以避免隐藏 bug，明确不需要重置状态的，可手动指定为 false。
  extraVisible?: MemStream<boolean> // 可额外指定一个 observable 来控制是否隐藏（在其他规则判断完成后才检查这个规则）
}
export interface CustomSidebar extends BaseSidebar {
  system: false
  id: number
  url: string
}
export type Sidebar = SystemSidebar | CustomSidebar

// 自定义侧边栏：Id => id, Name => name, Url => url | { system: false, url, scope, disabled }
// 系统侧边栏：Id => id, Name => random, Url => { system: true, key, disabled }
interface RespSidebar {
  Id: number
  Name: string
  Url: string
}
function formatRespSidebar(raw: RespSidebar): Sidebar | null {
  let detail = safeJSONParse<
    | Pick<CustomSidebar, 'system' | 'url' | 'scope' | 'disabled'>
    | Pick<SystemSidebar, 'system' | 'key' | 'disabled'>
  >(raw.Url)
  if (detail && detail.system) {
    const sidebar = systemSidebars.find(v => v.key === (detail as SystemSidebar).key)
    if (!sidebar) {
      logger.warn('找不到对应的系统侧边栏', raw)
      return null
    }
    return {
      id: raw.Id,
      ...sidebar,
      ...pick(detail, 'disabled'), // 只 pick 必要的字段，避免安全问题
    }
  } else {
    detail = {
      scope: [ContactType.external],
      disabled: false,
      url: raw.Url,
      ...(detail ?? {}),
      system: false,
    }
    return {
      id: raw.Id,
      name: raw.Name,
      key: `custom-${raw.Name}`,
      ...pick(detail, 'system', 'scope', 'disabled', 'url'), // 只 pick 必要的字段，避免安全问题
    }
  }
}
export function formatRespSidebars(rawItems: RespSidebar[]) {
  const items = rawItems.map(formatRespSidebar).filter((v): v is Sidebar => v !== null)
  const customSidebars = items.filter((v): v is CustomSidebar => !v.system)
  // 在线数据不一定定义了所有系统侧边栏（只有修改过的才有在线数据），所以要用本地数据来 map，有在线版本用在线的，没有用本地的
  const formattedSystemSidebars = systemSidebars.map(
    item => items.find(v => v.system && v.key === item.key) ?? item,
  )
  // 系统侧边栏排后面
  return [...customSidebars, ...formattedSystemSidebars]
}

const baseSystemSidebars: Omit<
  OptionalFields<SystemSidebar, 'supportObserving' | 'reset'>,
  'disabled' | 'system'
>[] = [
  {
    key: 'external-info',
    name: '客户资料',
    scope: [ContactType.external],
    supportObserving: true,
  },
  {
    key: 'words-library',
    name: '话术库',
    scope: [ContactType.external, ContactType.internal, ContactType.group],
    reset: false,
  },
  {
    key: 'new-rank',
    name: '新榜数据',
    scope: [ContactType.external],
    extraVisible: newRankConfigSubject.pipe(mmap(config => config?.enable === true)),
  },
  {
    key: 'group-info',
    name: '群资料',
    scope: [ContactType.group],
    supportObserving: true,
  },
  {
    key: 'group-members',
    name: '群成员',
    scope: [ContactType.group],
    supportObserving: true,
  },
  {
    key: 'group-tools',
    name: '群工具',
    scope: [ContactType.group],
  },
]
export const systemSidebars: SystemSidebar[] = baseSystemSidebars.map(v => ({
  supportObserving: false,
  reset: true,
  ...v,
  system: true,
  disabled: false,
}))
